package com.rq.shuduapp;


import java.util.ArrayList;
import java.util.List;


public class ShuDu {
    private final static Object[][] test = new Object[][]{
            {1, 2, 3, 4, 5, 6, 7, 8, 9},//
            {0, 0, 0, 0, 0, 0, 0, 0, 0},//
            {4, 5, 6, 7, 8, 9, 1, 2, 3},//
            {0, 0, 0, 0, 0, 0, 0, 0, 0},//
            {0, 0, 0, 0, 0, 0, 0, 0, 0},//
            {5, 6, 7, 8, 9, 1, 2, 3, 4},//
            {0, 0, 0, 0, 0, 0, 0, 0, 0},//
            {6, 7, 8, 9, 1, 2, 3, 4, 5},//
            {0, 0, 0, 0, 0, 0, 0, 0, 0}///
    };
//    private final static Object[][] que = new Object[][]{
//            {9, 0, 0, 0, 2, 0, 4, 0, 1},//{0, 5, 0, 0, 7, 0, 0, 4, 0},//{0, 0, 7, 0, 2, 0, 0, 0, 1},//{0, 8, 0, 9, 0, 0, 0, 3, 0},// {9, 0, 0, 0, 2, 0, 4, 0, 1},//{0, 0, 6, 3, 2, 5, 0, 0, 1},//{1, 0, 0, 0, 0, 0, 0, 0, 9},//
//            {0, 0, 5, 0, 9, 0, 0, 2, 0},//{4, 0, 0, 0, 8, 9, 7, 0, 0},//{3, 0, 0, 1, 5, 7, 0, 2, 0},//{0, 0, 9, 1, 0, 0, 0, 0, 0},// {0, 0, 5, 0, 9, 0, 0, 2, 0},//{3, 0, 0, 8, 1, 0, 0, 0, 5},//{0, 2, 0, 0, 0, 0, 0, 8, 0},//
//            {0, 4, 0, 1, 0, 0, 0, 9, 7},//{6, 7, 8, 3, 0, 0, 0, 0, 5},//{0, 2, 1, 0, 0, 4, 0, 9, 7},//{6, 0, 0, 0, 0, 0, 5, 0, 7},// {0, 4, 0, 1, 0, 0, 0, 9, 7},//{1, 9, 2, 4, 7, 6, 3, 0, 8},//{0, 0, 3, 0, 0, 0, 7, 0, 0},//
//            {5, 0, 0, 0, 0, 1, 0, 0, 0},//{0, 6, 4, 0, 0, 0, 0, 3, 0},//{0, 0, 2, 0, 0, 3, 0, 7, 0},//{0, 0, 2, 5, 4, 0, 0, 0, 6},// {5, 0, 0, 0, 0, 1, 0, 0, 0},//{0, 0, 0, 4, 1, 3, 0, 0, 9},//{0, 0, 0, 4, 0, 1, 0, 0, 0},//
//            {0, 0, 0, 0, 0, 0, 0, 0, 2},//{0, 1, 2, 0, 9, 6, 0, 0, 0},//{0, 3, 0, 7, 1, 0, 8, 0, 0},//{0, 3, 0, 0, 0, 2, 0, 0, 0},// {0, 0, 0, 0, 0, 0, 0, 0, 2},//{6, 0, 0, 0, 0, 0, 0, 0, 2},//{0, 0, 0, 0, 6, 0, 0, 0, 0},//
//            {4, 0, 0, 5, 7, 0, 3, 0, 9},//{0, 9, 5, 0, 0, 0, 0, 6, 0},//{1, 0, 5, 0, 0, 9, 0, 4, 0},//{1, 7, 0, 0, 0, 0, 0, 0, 3},// {4, 0, 0, 5, 7, 0, 3, 0, 9},//{0, 0, 5, 0, 2, 8, 0, 0, 0},//{0, 0, 0, 2, 0, 5, 0, 0, 0},//
//            {0, 5, 3, 0, 0, 2, 1, 8, 0},//{0, 0, 6, 4, 0, 0, 0, 0, 1},//{0, 5, 0, 2, 6, 1, 0, 8, 4},//{0, 0, 3, 0, 0, 0, 7, 0, 4},// {0, 5, 3, 0, 0, 2, 1, 8, 0},//{0, 8, 0, 0, 0, 0, 1, 2, 3},//{0, 0, 5, 0, 0, 0, 3, 0, 0},//
//            {0, 0, 0, 0, 0, 0, 0, 0, 0},//{1, 4, 0, 0, 2, 8, 6, 0, 0},//{2, 0, 0, 3, 7, 0, 0, 0, 0},//{2, 0, 0, 3, 0, 8, 0, 6, 0},// {0, 0, 0, 0, 0, 0, 0, 0, 0},//{0, 0, 4, 0, 0, 0, 5, 9, 7},//{0, 6, 0, 0, 0, 0, 0, 2, 0},//
//            {0, 0, 2, 8, 0, 0, 0, 0, 3}///{0, 8, 0, 0, 6, 0, 0, 2, 0} //{7, 0, 8, 4, 0, 5, 0, 1, 2}///{0, 0, 0, 0, 0, 0, 0, 0, 0} // {0, 0, 2, 8, 0, 0, 0, 0, 3} //{5, 0, 0, 0, 3, 0, 6, 0, 4} //{7, 0, 0, 0, 0, 0, 0, 0, 1}///
//    };

    private final static Object[][] que = new Object[][]{
            {0, 1, 0, 0, 0, 0, 0, 8, 0},//{1, 2, 3, 4, 5, 6, 7, 8, 9},//1, 2, 3, 4, 5, 6, 7, 8, 9
            {0, 2, 5, 0, 0, 6, 9, 0, 4},//{4, 5, 6, 7, 8, 9, 1, 2, 3},//4, 5, 6, 7, 8, 9, 1, 2, 3
            {6, 0, 0, 0, 0, 0, 2, 5, 0},//{7, 8, 9, 1, 2, 3, 4, 5, 6},//7, 8, 9, 1, 2, 3, 4, 5, 6
            {0, 0, 6, 5, 0, 8, 1, 9, 0},//{2, 0, 0, 0, 3, 0, 0, 0, 1},//0, 0, 0, 0, 0, 0, 0, 0, 0
            {0, 0, 0, 0, 0, 0, 0, 0, 0},//{5, 0, 0, 0, 4, 0, 0, 0, 2},//0, 0, 0, 0, 0, 0, 0, 0, 0
            {0, 8, 1, 9, 0, 3, 7, 0, 0},//{8, 0, 0, 0, 5, 0, 0, 0, 4},//0, 0, 0, 0, 0, 0, 0, 0, 0
            {0, 9, 4, 0, 0, 0, 0, 0, 7},//{9, 0, 0, 0, 6, 0, 0, 0, 5},//0, 0, 0, 0, 0, 0, 0, 0, 0
            {5, 0, 7, 8, 0, 0, 6, 4, 0},//{3, 0, 0, 0, 9, 0, 0, 0, 7},//0, 0, 0, 0, 0, 0, 0, 0, 0
            {0, 6, 0, 0, 0, 0, 0, 2, 0}///{6, 0, 0, 0, 7, 0, 0, 0, 8}///0, 0, 0, 0, 0, 0, 0, 0, 0
//            {"D", "6", "1", "8", "7", "5", "0", "3", "C,", "A", "E", "4", "B", "F", "2", "9"},
//            {"C", "A", "9", "B", "1", "E", "2", "4", "0,", "F", "3", "7", "6", "D", "8", "5"},
//            {"3", "E", "4", "2", "D", "6", "B", "9", "A,", "5", "1", "8", "F", "C", "0", "7"},
//            {"0", "7", "F", "5", "C", "_", "8", "D", "9,", "6", "B", "D", "E", "A", "4", "3"},
//            {"6", "B", "8", "F", "5", "C", "D", "0", "1,", "3", "A", "2", "7", "4", "9", "E"},
//            {"E", "9", "3", "C", "B", "4", "7", "1", "8,", "2", "D", "F", "0", "5", "6", "A"},
//            {"4", "2", "7", "0", "F", "8", "A", "E", "6,", "B", "9", "5", "C", "1", "3", "D"},
//            {"7", "5", "A", "D", "6", "3", "9", "2", "E,", "C", "4", "0", "1", "8", "F", "2"},
//            {"5", "F", "E", "6", "0", "D", "2", "7", "4,", "9", "8", "C", "3", "B", "A", "1"},
//            {"2", "3", "B", "4", "8", "1", "5", "A", "7,", "D", "F", "6", "9", "E", "C", "0"},
//            {"8", "C", "0", "A", "3", "9", "F", "6", "B,", "1", "5", "E", "2", "7", "D", "4"},
//            {"9", "1", "D", "7", "E", "F", "4", "C", "2,", "0", "A", "3", "5", "6", "B", "8"},
//            {"B", "4", "5", "9", "A", "E", "6", "F", "3,", "8", "2", "1", "D", "0", "7", "C"},
//            {"F", "D", "2", "3", "4", "0", "E", "8", "5,", "7", "C", "B", "A", "9", "1", "6"},
//            {"A", "8", "C", "0", "2", "7", "1", "B", "D,", "E", "6", "9", "4", "3", "5", "F"},
//            {"1", "0", "6", "_", "9", "_", "3", "5", "F,", "4", "0", "A", "8", "2", "E", "B"}
//            {1, 2, 3, 4},
//            {3, 4, 1, 2},
//            {0, 0, 0, 0},
//            {0, 0, 0, 0},

    };

//      847 926 531   587 926 431     986 725 431
//      396 157 428   349 157 628     315 49_ 826
//      521 834 697   621 834 597     24_ 186 597
//      682 543 179   892 543 176     579 231 648
//      439 712 856   436 712 859     83_ 649 752
//      175 689 243   175 689 243     461 578 3_9
//      953 261 784   953 261 784     753 962 184
//      214 378 965   214 378 965     698 314 275
//      768 495 312   768 495 312     1_2 857 963
//    private final static Object[][] que = new Object[][]{
//            {1, 0, 0, 2},//
//            {0, 2, 0, 0},//
//            {0, 0, 3, 0},//
//            {0, 0, 0, 4}//
//    };

//      0:MFAH GEPC LJND KOBI
//      1:LJIK ANBD POCG FMHE
//      2:CNDB MFKI JEAH OLPG
//      3:PGOE L_HM IFKM NJDC
//      4:FKHO ELMP ACJB GDIN
//      5:NICL KDGA HBMO PEFJ
//      6:DBGP OHJN FKIE LACM
//      7:GEJM FCIB NLDP AHOB
//      8:EONF PMBG DIHL CKJA
//      9:BCKD HAEJ GMOF INLP
//      1:HLPJ CIOF KAEN BGMD
//      2:IAMG NODL BPJC EFKH
//      3:KDEI JNFO CHBA MPGL
//      4:OMBC DPNH EGLK JIAF
//      5:JHLP BGAK MNFI DCEO
//      6:APF_ I_CE ODPJ HBNK

    //    private final static String rules = "1234";
    private final static String rules = "123456789";

    public static void main(String[] args) {
        Object[][] que = ShuDu.que;//getQueFromStr();
        printAll(que);
        final Calculate2 mCalculate = new Calculate2(que, rules);
//        Calculate.init(que, rules);
        final Object[][] res = new Object[que.length][que.length];
        for (int i = 0; i < que.length; i++) {
            for (int k = 0; k < que[i].length; k++) {
                if (rules.contains(String.valueOf(que[i][k]))) {
                    res[i][k] = que[i][k];
                }
            }
        }
        final long startTime = System.currentTimeMillis();
        new Thread(new Runnable() {
            boolean hasNext = true;

            @Override
            public void run() {
                while (hasNext) {
                    Row2 item = mCalculate.getNext();
                    if (item == null) {
//                        printLog("====================");
//                        mCalculate.printAll();
//                        printLog("====================");
//                        item = mCalculate.guessOne();
//                        if (item != null) {
//                            System.err.println(item.writeTime + "[" + item.guessValueRes + "] 猜测:" + item.locTxt() + ">" + item.value);
//                            guessStep.add(item);
//                        }
                    } else {
//                        System.err.println(item.writeTime + " 计算:" + item.locTxt() + ">" + item.value);
                    }
                    if (item != null) {
//                        setData2View(item.getX(), item.getY(), String.valueOf(item.getValue()), Color.RED);
//                        steps.add(item);
//                        System.out.print("<" + item.writeTime + ">:");
//                        printLog(item.locTxt() + "--(" + item.way + ")-->" + item.getValue());
                        res[item.getX()][item.getY()] = item.getValue();
//                        mCalculate.synchronization(res);
//                        System.out.println("(" + item.locTxt() + "):" + item.value);
//                        printLog("\n");
//                        printAll(res);
                    } else {
                        hasNext = false;
                    }
                    if (!hasNext) {
                        boolean r = Calculate.isOk(res, rules);
                        if (mCalculate.rollBack()) {
                            hasNext = true;
                            continue;
                        }
//                        if (!r && guessStep.size() > 0) {
////                            System.out.println("开始溯源:");
//                            Row2 lastGuess = findLastCanWriteGuess();
//                            if (lastGuess == null) return;
//
//                            printAll(res);
//                            System.out.println("=================");
////                            LOG.e("ShuDu", "130:" + steps.size());
//                            int lastIndex = steps.indexOf(lastGuess);
//                            for (int i = steps.size() - 1; i >= lastIndex; i--) {
//                                Row2 remove = steps.remove(i);
//                                res[remove.getX()][remove.getY()] = "_";
//                            }
//                            lastGuess.value = lastGuess.guessValueRes.substring(lastGuess.guessIndex + 1, lastGuess.guessIndex + 2);
//                            lastGuess.guessIndex++;
////                            System.out.println("<" + lastGuess.locTxt() + ">新猜测为:" + lastGuess.value);
//                            guessStep.add(lastGuess);
//                            steps.add(lastGuess);
////                            LOG.e("ShuDu", "137:" + steps.size());
//                            res[lastGuess.getX()][lastGuess.getY()] = lastGuess.getValue();
////                            printAll(res);
////                            System.out.println("=================");
//                            mCalculate.synchronization(res);
//                            hasNext = true;
//                            continue;
//                        }
                        System.out.println("计算结果:" + r);
                        System.out.println("用时:" + (System.currentTimeMillis() - startTime) + "毫秒");
                        hasNext = false;
                        printAll(res);
                    }

                }
            }

//            private Row2 findLastCanWriteGuess() {
//                if (guessStep.size() == 0) {
//                    System.out.println("没有猜测");
//                    return null;
//                }
//                Row2 lastGuess = guessStep.remove(guessStep.size() - 1);
//                while (lastGuess == null && guessStep.size() > 0) {
//                    lastGuess = guessStep.remove(guessStep.size() - 1);
//                }
//                if (lastGuess == null) {
//                    System.out.println("没有更多猜测");
//                    return null;
//                }
//                if (lastGuess.guessIndex < lastGuess.guessValueRes.length() - 1) {
////                    System.out.println("寻找到可回溯:" + lastGuess.toString());
//                    return lastGuess;
//                } else {
//                    return findLastCanWriteGuess();
//                }
//            }
        }).

                start();

    }


    private static Object[][] getQueFromStr() {
        String ors = "--1----3-----6-9\n" +
                "-1--1-2-0-CGF-8-\n" +
                "--4--6-9-5----0-\n" +
                "-7-EL-8----4-1--\n" +
                "----5----3--7---\n" +
                "-9--2-GA-2---5-1\n" +
                "4-GP--1-6----1--\n" +
                "-5---3-2--DP--6-\n" +
                "5--6-4--4--3-2-1\n" +
                "-3--------6-9-3-\n" +
                "8-0-3--6-1--2---\n" +
                "---7-OD---1----8\n" +
                "2---1----8-1-0-3\n" +
                "--2--0--5--2--1-\n" +
                "-8--2--2--FI-3--\n" +
                "--6---3--4--8-5-\n";
        Object[][] que = new Object[rules.length()][rules.length()];
        String[] from = ors.split("\n");
        for (int i = 0; i < rules.length(); i++) {
            for (int k = 0; k < rules.length(); k++) {
                try {
                    que[i][k] = from[i].charAt(k);
                } catch (Exception e) {

                }
            }
        }
        return que;
    }

    private static void printAll(Object[][] res) {
        int sqrt = (int) Math.sqrt(res.length);
        for (int i = 0; i < res.length; i++) {
            for (int k = 0; k < res[i].length; k++) {
                if (k == 0) System.out.print(rules.charAt(i) + ":");
                System.out.print(isEmpty(res[i][k]) ? "_" : res[i][k]);
                if ((k + 1) % sqrt == 0) System.out.print(" ");
            }
            System.out.println();
        }
    }

    public static boolean isEmpty(Object con) {
        try {
            return con == null
                    || con instanceof Integer && (int) con == 0
                    || con instanceof String && !rules.contains((String) con)
                    || con instanceof CharSequence && !rules.contains((CharSequence) con)
                    || con instanceof Character && !rules.contains(String.valueOf(con));


        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(rules);
            System.out.println(con);
            return true;
        }
    }

    private static boolean checkStepIn(Row row, Object[][] res) {
        if (row == null) return false;
        int sqrt = (int) Math.sqrt(res.length);
        for (int x = 0; x < res.length; x++) {
            for (int y = 0; y < res.length; y++) {
                if (row.getX() == x && row.getY() != y && isSame(row.getValue(), res[x][y])) {
                    //同行不同列
                    printLog("Hang.error." + x + ">>>" + getError(res, 0, x));
                    return false;
                }
                if (row.getX() != x && row.getY() == y && isSame(row.getValue(), res[x][y])) {
                    //同列不同行
                    printLog("Lie.error." + y + ">>>" + getError(res, 1, y));
                    return false;
                }

                for (int sqrX = row.sqrX * sqrt; sqrX < row.sqrX * sqrt + sqrt; sqrX++) {
                    for (int sqrY = row.sqrY * sqrt; sqrY < row.sqrY * sqrt + sqrt; sqrY++) {
                        if (isSame(row.getValue(), res[sqrX][sqrY]) && (sqrX != row.x || sqrY != row.y)) {
                            printLog("Kuai.error." + row.getSqrIndex() + ">>>" + getError(res, 2, row.getSqrIndex()));
                            //同块数据相同
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * @param res  源数据
     * @param type 0-行 1-列 2-块
     * @param key  相应下标
     * @return
     */
    private static String getError(Object[][] res, int type, int key) {
        StringBuffer sb = new StringBuffer();
        if (type == 0) {
            for (Object o : res[key]) {
                sb.append(strObj(o));
            }
        } else if (type == 1) {
            for (int i = 0; i < rules.length(); i++) {
                sb.append(strObj(res[i][key]));
            }
        } else {
            int sqr = (int) Math.sqrt(rules.length());
            int xStart = key / sqr;
            int yStart = key % sqr;
            for (int x = xStart; x < xStart + sqr; x++) {
                for (int y = yStart; y < yStart + sqr; y++) {
                    sb.append(strObj(res[x][y]));
                }
            }
        }
        return sb.toString();
    }

    private static String strObj(Object obj) {
        if (obj == null) return "";
        return obj instanceof Row ? ((Row) obj).value == null ? "" :
                String.valueOf(((Row) obj).value) : String.valueOf(obj)
                ;
    }

    private static boolean isSame(Object o1, Object o2) {
        if (!isEmpty(o1) && !isEmpty(o2)) {
            return String.valueOf(o1).equals(String.valueOf(o2));
        }
        return false;
    }


    private static void printLog(String... con) {
        if (con == null || con.length == 0) {
            System.out.println();
        } else {
            for (String s : con) {
                System.out.println(s);
            }
        }
    }
}
